//
// AutoPtr.h
//
// $Id: //poco/1.2/Foundation/include/Poco/AutoPtr.h#3 $
//
// Library: Foundation
// Package: Core
// Module:  AutoPtr
//
// Definition of the AutoPtr template class.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#ifndef XPlus_AutoPtr_INCLUDED
#define XPlus_AutoPtr_INCLUDED


//#include "Poco/Foundation.h"
#include "XPlus/Exception.h"
#include <algorithm>


namespace XPlus {


  template <class C>
    class AutoPtr
    /// AutoPtr is a "smart" pointer for classes implementing
    /// reference counting based garbage collection.
    /// To be usable with the AutoPtr template, a class must
    /// implement the following behaviour:
    /// A class must maintain a reference count.
    /// The constructors of the object initialize the reference
    /// count to one.
    /// The class must implement a public duplicate() method:
    ///     void duplicate();
    /// that increments the reference count by one.
    /// The class must implement a public release() method:
    ///     void release()
    /// that decrements the reference count by one, and,
    /// if the reference count reaches zero, deletes the
    /// object.
    ///
    /// AutoPtr works in the following way:
    /// If an AutoPtr is assigned an ordinary pointer to
    /// an object (via the constructor or the assignment operator),
    /// it takes ownership of the object and the object's reference 
    /// count remains unchanged.
    /// If the AutoPtr is assigned another AutoPtr, the
    /// object's reference count is incremented by one by
    /// calling duplicate() on its object.
    /// The destructor of AutoPtr calls release() on its
    /// object.
    /// AutoPtr supports dereferencing with both the ->
    /// and the * operator. An attempt to dereference a null
    /// AutoPtr results in a NullPointerException being thrown.
    /// AutoPtr also implements all relational operators.
    /// Note that AutoPtr allows casting of its encapsulated data types.
    {
      public:
        AutoPtr(): _ptr(0)
      {
        if (_ptr) _ptr->duplicate(); //satya
      }

        AutoPtr(C* ptr): _ptr(ptr)
      {
        if (_ptr) _ptr->duplicate(); //satya
      }

        AutoPtr(C* ptr, bool shared): _ptr(ptr)
      {
        if (shared && _ptr) _ptr->duplicate();
      }

        AutoPtr(const AutoPtr& ptr): _ptr(ptr._ptr)
      {
        if (_ptr) _ptr->duplicate();
      }

        template <class Other> 
          AutoPtr(const AutoPtr<Other>& ptr): _ptr(const_cast<Other*>(ptr.get()))
        {
          if (_ptr) _ptr->duplicate();
        }

        ~AutoPtr()
        {
          if (_ptr) _ptr->release();
        }

        AutoPtr& assign(C* ptr)
        {
          if (_ptr != ptr)
          {
            if (_ptr) _ptr->release();
            _ptr = ptr;
            if (_ptr) _ptr->duplicate(); //satya
          }
          return *this;
        }

        AutoPtr& assign(C* ptr, bool shared)
        {
          if (_ptr != ptr)
          {
            if (_ptr) _ptr->release();
            _ptr = ptr;
            if (shared && _ptr) _ptr->duplicate();
          }
          return *this;
        }

        AutoPtr& assign(const AutoPtr& ptr)
        {
          if (&ptr != this)
          {
            if (_ptr) _ptr->release();
            _ptr = ptr._ptr;
            if (_ptr) _ptr->duplicate();
          }
          return *this;
        }

        template <class Other> 
          AutoPtr& assign(const AutoPtr<Other>& ptr)
          {
            if (ptr.get() != _ptr)
            {
              if (_ptr) _ptr->release();
              _ptr = const_cast<Other*>(ptr.get());
              if (_ptr) _ptr->duplicate();
            }
            return *this;
          }

        AutoPtr& operator = (C* ptr)
        {
          return assign(ptr);
        }

        AutoPtr& operator = (const AutoPtr& ptr)
        {
          return assign(ptr);
        }

        template <class Other> 
          AutoPtr& operator = (const AutoPtr<Other>& ptr)
          {
            return assign<Other>(ptr);
          }

        void swap(AutoPtr& ptr)
        {
          std::swap(_ptr, ptr._ptr);
        }

        template <class Other> 
          AutoPtr<Other> cast() const
          /// Casts the AutoPtr via a dynamic cast to the given type.
          /// Returns an AutoPtr containing NULL if the cast fails.
          /// Example: (assume class Sub: public Super)
          ///    AutoPtr<Super> super(new Sub());
          ///    AutoPtr<Sub> sub = super.cast<Sub>();
          ///    poco_assert (sub.get());
          {
            Other* pOther = dynamic_cast<Other*>(_ptr);
            return AutoPtr<Other>(pOther, true);
          }

        C* operator -> ()
        {
          if (_ptr)
            return _ptr;
          else
            throw NullPointerException();
        }

        const C* operator -> () const
        {
          if (_ptr)
            return _ptr;
          else
            throw NullPointerException();
        }

        C& operator * ()
        {
          if (_ptr)
            return *_ptr;
          else
            throw NullPointerException();
        }

        const C& operator * () const
        {
          if (_ptr)
            return *_ptr;
          else
            throw NullPointerException();
        }

        C* get()
        {
          return _ptr;
        }

        const C* get() const
        {
          return _ptr;
        }

        operator C* ()
        {
          return _ptr;
        }

        operator const C* () const
        {
          return _ptr;
        }

        bool operator ! () const
        {
          return _ptr == 0;
        }

        bool isNull() const
        {
          return _ptr == 0;
        }

        C* duplicate()
        {
          if (_ptr) _ptr->duplicate();
          return _ptr;
        }

        bool operator == (const AutoPtr& ptr) const
        {
          return _ptr == ptr._ptr;
        }

        bool operator == (const C* ptr) const
        {
          return _ptr == ptr;
        }

        bool operator == (C* ptr) const
        {
          return _ptr == ptr;
        }

        bool operator != (const AutoPtr& ptr) const
        {
          return _ptr != ptr._ptr;
        }

        bool operator != (const C* ptr) const
        {
          return _ptr != ptr;
        }

        bool operator != (C* ptr) const
        {
          return _ptr != ptr;
        }

        bool operator < (const AutoPtr& ptr) const
        {
          return _ptr < ptr._ptr;
        }

        bool operator < (const C* ptr) const
        {
          return _ptr < ptr;
        }

        bool operator < (C* ptr) const
        {
          return _ptr < ptr;
        }

        bool operator <= (const AutoPtr& ptr) const
        {
          return _ptr <= ptr._ptr;
        }

        bool operator <= (const C* ptr) const
        {
          return _ptr <= ptr;
        }

        bool operator <= (C* ptr) const
        {
          return _ptr <= ptr;
        }

        bool operator > (const AutoPtr& ptr) const
        {
          return _ptr > ptr._ptr;
        }

        bool operator > (const C* ptr) const
        {
          return _ptr > ptr;
        }

        bool operator > (C* ptr) const
        {
          return _ptr > ptr;
        }

        bool operator >= (const AutoPtr& ptr) const
        {
          return _ptr >= ptr._ptr;
        }

        bool operator >= (const C* ptr) const
        {
          return _ptr >= ptr;
        }

        bool operator >= (C* ptr) const
        {
          return _ptr >= ptr;
        }

      private:
        C* _ptr;
    };


  template <class C>
    inline void swap(AutoPtr<C>& p1, AutoPtr<C>& p2)
    {
      p1.swap(p2);
    }


} // namespace XPlus


#endif // XPlus_AutoPtr_INCLUDED
